package com.sailing.study.algorithm.binary;

/**
 *
 * 写在最前面
 * 这是本人在研究订单号使用号码段生成时 重新学习二进制操作的首篇
 *
 * 需要搞明白的几个重点知识
 * 1. 正数 & 负数 （int 32bit, long double 64bit）关系
 *   1.1 原码 反码 补码
 *
 * 2. & 与操作(按位与):
 * 【解义】对两个整数的二进制形式逐位进行逻辑与 运算，原理:1|0=0,0|0=0,1&1=1;0&1=0等。
 *
 * 3. | 或操作(按位或):
 * 【解义】对两个整数的二进制形式逐位进行逻辑或运算，原理为:1|0=1,0|0=0,1|1=1,0|1=1 等。
 *
 * 4. ~ 取反
 *
 * 5. ^ 异或(按 位异或):
 * 【解义】对两个整数的二进制形式逐位进行逻辑异或运算，原理:1^1=0,1^0=1,0^1=1,0^0=0.
 * 4^-5：
 4的二进制形式为：00000000 00000000 00000000 00000100，
 -5的二进制形式为：11111111 11111111 11111111 11111011，
 逐位进行逻辑异或运算：11111111 11111111 11111111 11111111，即得到-1.

 实际应用：按位异或可以比较两个数字是否相等，它利用 1^1=0，0^0=0的原理。  20^20==0
 *
 * 6. << 数值位移 ，左移
 *  m<<n 的含义:把整数m表示的二进制数左移n位,高位移出n位都舍弃，低位补0.  (此时将会出现正数变成负数的形式)
 * 实例：
 3<<2剖析：
 3二进制形式: 00000000 00000000 00000000 00000011,按照$1的原理，得到00000000 00000000 00000000 00001100,即为12.

 左移使整数变为负数:
 10737418<<8
 10737418二进制表示形式:00000000 10100011 11010111 00001010,按照$1的原理，得到10100011 11010111 00001010 00000000，即为:-1546188288.

 * 7. >>
 *  m>>n 的含义:把整数m表示的二进制数右移n位,m为正数，高位全部补0；m为负数，高位全部补1.
 *
 * 8. >>> 无符号右移
 *  m>>>n 整数m表示的二进制右移n位，不论正负数，高位都补零。
 *
 *  注意： 6 7 8 举例，如果n为负数:这时JVM会先让n对32取模，变成一个绝对值小于32的负数，然后再加上32，直到 n 变成一个正数
 *
 *   综上所述:
 * m<<n即在数字没有溢出的前提下，对于正数和负数，左移n位都相当于m乘以2的n次方.
 *  m>>n即相当于m除以2的n次方，得到的为整数时，即为结果。如果结果为小数，此时会出现两种情况：
  (1)如果m为正数，得到的商会无条件 的舍弃小数位；
 (2)如果m为负数，舍弃小数部分，然后把整数部分加+1得到位移后的值。

 * 9. <<< 在Java中，这是一个伪命题
 *
 * 10 同或 在Java中没有直接的操作符，
 *
 * Created by chao.chen on 2019/3/13.
 */
public class Long2Binary {

    public static void main(String[] args) {

        Long p1= 1L;
        String pbs = Long.toBinaryString(p1);
        System.out.println(pbs + ", len :" + pbs.length());
        /**
         * 从这里我们可以得出结论
         * long 64bit
         * -1L，二进制表示，即为64个1
         */
        Long negative = -1L;
        String nbs = Long.toBinaryString(negative);
        System.out.println(nbs + ", len :" + nbs.length());
        /**
         * 正数 -> 负数
         * 正数转二进制 ，取反，以10进制数值 + 1
         */
        long b1= ~p1;
        System.out.println("~1 -> "+ b1 + ", binary -> "+ Long.toBinaryString(b1));
        Long tn = ~p1 + 1L ;
        System.out.println("test ~1L + 1L ="+ tn);
        /**
         * 64位的1L,取反后是高位63个1，低位1个0；like: 1...10
         * so get result : 1...10 * 1L == 0
         */
        long tn1 = b1 & 1L;
        System.out.println("test ~1L & 1L ="+ tn1);
        /**
         *
         * 这里是一个实际的使用场景
         * 订单号 采用了号段，自增序列段使用的位数
         * -1L ^ (-1L << 10)
         * 有了前面的知识 -1L 2进制表示为64个1
         * -1L << 10 -->   low位去掉10个1，high bit :54个1 , 即 1....10...0
         */
        long lmn11 = -1L << 10;
        System.out.println("-1L << 10 ->" + lmn11 + ",binary string :" + Long.toBinaryString(lmn11));
        long seqBitsMask =  -1L ^ (-1L << 10);

        System.out.println("seqBitsMask long value :"+ seqBitsMask + ", binary string :"+ Long.toBinaryString(seqBitsMask));
        long sequence = 1023L;
        //sequence++;
        sequence &= seqBitsMask;
        System.out.println(" 0L after ++ , & 1111111111 :" + sequence);


        long v1024 = 1024L;
        String s1024;
        System.out.println(v1024 + "-->" + (s1024=Long.toBinaryString(v1024)));


    }
}
